home *** CD-ROM | disk | FTP | other *** search
- /*************************************************
- CDigitalControl.c
-
- The DigitalControl Class
-
- This is NOT a Macintosh control with a CNTL
- resource. It is a specialized sort of 'control'
- with two buttons and a digital display, useful
- for selecting a value when high precision and
- interactive value display are needed. A variable-
- speed mechanism allows for fast selection of the
- desired value, while a tick-related delay control
- keeps the reaction time independent from CPU
- speed.
-
- SUPERCLASS = CPane
-
- © 1989 Enrico Colombini. All rights reserved.
- *************************************************/
-
- #include "CDigitalControl.h"
- #include <stdio.h> /*for sprintf*/
- #include <string.h>
-
- /*************************************************
- Class library globals accessed by CDigitalControl
- *************************************************/
- /*the view the mouse went down into*/
- extern CView *gLastViewHit;
- /*event record of last mouse down*/
- extern EventRecord gLastMouseDown;
-
- /*************************************************
- Toolbox-called local procedure, not part of the
- CDigitalControl object
- *************************************************/
- static pascal void Track(
- ControlHandle macControl,short whichPart);
-
- /*************************************************
- IDigitalControl
-
- Initialize a CDigitalControl object. The
- intialization is typical of an object descending
- from the CView class. However, there is no rType
- parameter and the resID parameter is used to load
- four related object templates from the resource
- fork: a Pane, a Button, a Border and a Static
- Text. They must all have the same resID.
- *************************************************/
- void CDigitalControl::IDigitalControl(
- short resID, /*for Pane, btn, Bord, StTx*/
- CView *anEnclosure,
- CBureaucrat *aSupervisor)
- {
- Rect r;
-
- inherited::IViewRes( /*first, init main pane*/
- 'Pane',resID,anEnclosure,aSupervisor);
-
- dnBtn = new(CButton); /*create down button, « */
- dnBtn->IButton(resID,this,this);
- dnBtn->SetTitle((unsigned char *)"\p«");
- dnBtn->SetActionProc(Track); /*set re-entry*/
-
- GetFrame(&grayRect); /*prepare gray rectangle*/
- dnBtn->GetFrame(&r);
- InsetRect(&grayRect,r.right,0); /*between btns*/
-
- upBtn = new(CButton); /*create up button, » */
- upBtn->IButton(resID,this,this);
- upBtn->Offset(grayRect.right,0,FALSE); /*align*/
- upBtn->SetTitle((StringPtr)"\p»");
- upBtn->SetActionProc(Track); /*set re-entry*/
-
- border = new(CBorder); /*create border*/
- border->IViewRes('Bord',resID,this,this);
- border->CenterWithinEnclosure(TRUE,TRUE);
-
- disp = new(CStaticText); /*create display*/
- disp->IViewRes('StTx',resID,border,this);
- disp->FitToEnclosure(TRUE,TRUE); /*inside Bord*/
- disp->SetFontName((StringPtr)"\pMonaco");
- disp->SetFontSize(12);
- disp->SetAlignment(teJustCenter); /*center*/
-
- minValue = 0; /*set defaults*/
- maxValue = 100;
- SetValue(minValue); /*set current value*/
- stepSlow = 1;
- stepFast = 5;
- threshold = 20;
- firstDelay = 18; /*300 msec*/
- reptDelay = 6; /*100 msec*/
-
- lastDown = -1L; /*ensure difference*/
- nextWhen = 0L; /*ensure acceptance*/
- trackSpeed = trackCount = 0; /*not tracking*/
-
- displayCmd = 0L; /*don't disturb boss*/
- }
-
- /*************************************************
- Draw {OVERRIDE}
-
- Draw the CDigitalControl object. Apart from the
- gray rectangle between the two buttons, the
- initialization is done automatically by the
- methods inherited from the superclass(es). Note
- that, as FillRect may move memory, it is unsafe
- to pass the address of the instance variable
- grayRect. Passing a local variable (r) is ok.
- *************************************************/
- void CDigitalControl::Draw(Rect *area)
- {
- Rect r = grayRect; /*FillRect may move mem!*/
-
- FillRect(&r,gray);
- inherited::Draw(area);
- }
-
- /************************************************
- Track {NOT AN OBJECT METHOD - called by Toolbox}
-
- Called by Toolbox's TrackControl when the user
- holds down the mouse button inside one of the
- DigitalControl buttons. It can re-enter this
- object by referring to the TCL global variable
- gLastViewHit, which record the object the mouse
- went down into (it). The supervisor of this
- button is our DigitalControl object. The pointer
- to (it) is passed to the TrackValue method to
- tell it what button is currently pressed. After
- the tracking, the drawing environment of the
- original button must be restored for the Toolbox
- to work properly.
- *************************************************/
- static pascal void Track(
- ControlHandle macControl, short whichPart)
- {
- CView *it;
-
- it = gLastViewHit; /*identify caller*/
-
- ((CDigitalControl *)(it->itsSupervisor))
- ->TrackValue(it); /*Track!*/
-
- it->Prepare(); /*restore environment*/
- }
-
- /*************************************************
- TrackValue
-
- Called repeatedly (by way of pascal Track, above)
- while the mousebutton is hold down inside one of
- the DigitalControl buttons. The global variable
- gLastMouseDown is used to differentiate the first
- call after the mouse was pressed, to implement
- the 3-speed step control of the value change.
- *************************************************/
- void CDigitalControl::TrackValue(CView *btn)
- {
- short first;
- short step;
- short dir;
-
- /*check if 1st entry, exit if not yet time*/
- first = (gLastMouseDown.when != lastDown);
- if (! first && TickCount() < nextWhen)
- return;
-
- /*if 1st entry: record time, set 1st delay*/
- if (first) {
- lastDown = gLastMouseDown.when;
- nextWhen = TickCount()+firstDelay;
- trackSpeed = 1;
- } else { /*not 1st entry, set repeat delay*/
- nextWhen = TickCount()+reptDelay;
- if (trackSpeed == 1) { /*2nd speed*/
- trackSpeed = 2;
- trackCount = threshold-1; /*countdown*/
- } else {
- if (--trackCount == 0) { /*3rd speed*/
- trackSpeed = 3;
- }
- }
- }
-
- /*choose step, reverse if down button*/
- step = (trackSpeed < 3) ? stepSlow : stepFast;
- if (btn == dnBtn) step = -step;
-
- SetValue(value+step); /*set display value*/
- UpdateDisplayNow(); /*update immediately*/
- }
-
- /*************************************************
- SetValue
-
- Set current value, update display text in memory.
- Screen update will happen at the next update
- event. If no displayCmd has been set, a default
- 5-digit numerical display is used. If a
- displayCmd has been set, a DoCommand message is
- sent to the DigitalControl's supervisor. It may
- set the text to display as it likes by means of
- the SetDisplayText method.
- *************************************************/
- void CDigitalControl::SetValue(short val)
- {
- char v[7]; /*display buffer*/
-
- value = val; /*set new value, check it*/
- if (value < minValue) value = minValue;
- if (value > maxValue) value = maxValue;
-
- if (displayCmd == 0L) { /*in-house display*/
- sprintf(v,"%05d",value); /*build disp. text*/
- SetDisplayText(v); /*set for display*/
- } else { /*ask boss to display as it pleases*/
- itsSupervisor->DoCommand(displayCmd);
- }
- }
-
- /*************************************************
- SetDisplayText
-
- Set the text to display. Called by SetValue,
- directly or indirectly through the
- DigitalControl's supervisor DoCommand method.
- *************************************************/
- void CDigitalControl::SetDisplayText(char *txt)
- {
- /*update internal text*/
- disp->SetTextPtr(txt,strlen(txt));
- }
-
- /*************************************************
- UpdateDisplayNow
-
- Update the text shown on the screen without
- waiting for an update event. Used during the
- tracking of one of the two buttons. Make sure
- that the text won't be updated again when the
- mouse button is released. A subclass of
- DigitalControl may choose to update the display
- faster by drawing the text directly using a
- Tollbox call, thus also removing the slight
- flicker during the update.
- *************************************************/
- void CDigitalControl::UpdateDisplayNow(void)
- {
- Rect r;
- GrafPtr gp;
-
- disp->GetFrame(&r); /*ready to draw*/
- gp = disp->GetMacPort();
-
- BeginUpdate(gp); /*don't redraw later*/
- disp->Prepare(); /* but draw now*/
- disp->Draw(&r);
- EndUpdate(gp);
- }
-
- /*************************************************
- SetMinValue
-
- Set the minimum allowed value, check ≤ max.
- *************************************************/
- void CDigitalControl::SetMinValue(short val)
- {
- minValue = val;
- if (minValue > maxValue) minValue = maxValue;
- if (value < minValue) SetValue(minValue);
- }
-
- /*************************************************
- SetMaxValue
-
- Set the maximum value allowed, check ≥ min.
- *************************************************/
- void CDigitalControl::SetMaxValue(short val)
- {
- maxValue = val;
- if (maxValue < minValue) maxValue = minValue;
- if (value > maxValue) SetValue(maxValue);
- }
-
- /*************************************************
- SetSteps
-
- Set single & slow speed step, high speed step,
- and number of steps before changing speed
- (threshold).
- *************************************************/
- void CDigitalControl::SetSteps(
- short slow, short fast, short thr)
- {
- stepSlow = slow;
- stepFast = fast;
- threshold = thr;
- }
-
- /*************************************************
- SetDisplayCmd
-
- Set command number to send to supervisor while
- tracking.
- *************************************************/
- void CDigitalControl::SetDisplayCmd(long cmd)
- {
- displayCmd = cmd; /*setup callback*/
- SetValue(value); /*boss, please update*/
- }
-
- /*************************************************
- GetValue
-
- Return current value: so this object does
- something, after all!
- *************************************************/
- short CDigitalControl::GetValue(void)
- {
- return value;
- }
-
-